using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Xml.Schema;
using Autofac;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using uTILLIty.Rave.Contract.Configuration;
using uTILLIty.Rave.Contract.Job;
using uTILLIty.Rave.Contract.StorageAdapter;
using uTILLIty.Rave.Core.Configuration;
using uTILLIty.Rave.Core.StorageAdapter;
using uTILLIty.Rave.Core.Strategy;

namespace uTILLIty.Rave.Core
{
  public class TestBase
  {
    public TestBase()
    {
      var thread = System.Threading.Thread.CurrentThread;
      thread.CurrentCulture = thread.CurrentUICulture = new CultureInfo("en-US");
    }

    public IStorageAdapter StorageAdapter { get; set; }

    public TestContext TestContext { get; set; }

    private IContainer _container;
    protected IContainer Container
    {
      get
      {
        if (_container == null)
        {
          var builder = GetBuilder();
          _container = Build(builder);
        }
        return _container;
      }
      set { _container = value; }
    }

    protected ContainerBuilder GetBuilder()
    {
      var builder = new ContainerBuilder();
	    var coreModule = new IocModule();
			builder.RegisterModule(coreModule);
			coreModule.RegisterByKey<UnitTestConfigurationValidatorStrategy, IConfigurationValidatorStrategy>(builder, WellKnownStrategies.Default).SingleInstance();
			return builder;
    }

		protected IContainer Build(ContainerBuilder builder)
    {
      var container = builder.Build();
      return container;
    }

    protected virtual XmlSchemaSet GetValidationSchemas()
    {
      var set = new XmlSchemaSet();
      foreach (var schema in Container.Resolve<IEnumerable<XmlSchema>>())
        set.Add(schema);
      return set;
    }

    protected Contract.Configuration.Configuration LoadConfig(string configFile)
    {
      using (var configData = File.OpenRead(configFile))
      {
        // ReSharper disable ConditionIsAlwaysTrueOrFalse
        Contract.Configuration.Configuration target = null;
        // ReSharper disable ExpressionIsAlwaysNull
        target = target.Load(configData, GetValidationSchemas());
        // ReSharper restore ExpressionIsAlwaysNull
        return target;
        // ReSharper restore ConditionIsAlwaysTrueOrFalse
      }
    }

    protected void InitTraceSource(Job job)
    {
      job.LogLevel = SourceLevels.All;
      job.TraceSource = new TraceSource("Job" + job.JobId, job.LogLevel);
      if (job.LogLevel != SourceLevels.Off)
        job.TraceSource.Listeners.Add(new ConsoleTraceListener());
    }

    protected readonly StorageMember AdminsStorageMember = new StorageMember("S-1-2-3", "Administrators");
    protected readonly StorageMember UsersStorageMember = new StorageMember("S-1-19-7", "Users");
    protected readonly StorageMember JohnStorageMember = new StorageMember("S-1-7-15", "John");
    protected readonly StorageMember SystemStorageMember = new StorageMember("S-1-3-6", "System");
    protected readonly StorageMember MikeStorageMember = new StorageMember("S-1-4-8", "Mike");

    private void CreateStorageAdapterMock(Contract.Configuration.Configuration config)
    {
      StorageAdapter = MockRepository.GenerateMock<IStorageAdapter>();
      StorageAdapter.Stub(s => s.DoRightsDiffer("", "")).IgnoreArguments().Return(false)
        .WhenCalled(m => m.ReturnValue = DoRightsDiffer((string)m.Arguments[0], (string)m.Arguments[1]));
      StorageAdapter.Stub(s => s.TryResolveMember(config.Members.Single(m => m.ID == "Admins")))
        .Return(AdminsStorageMember);
      StorageAdapter.Stub(s => s.TryResolveMember(config.Members.Single(m => m.ID == "Users")))
        .Return(UsersStorageMember);
      StorageAdapter.Stub(s => s.TryResolveMember(config.Members.Single(m => m.ID == "John")))
        .Return(JohnStorageMember);
      StorageAdapter.Stub(s => s.TryResolveMember(config.Members.Single(m => m.ID == "Mike")))
        .Return(MikeStorageMember);
      StorageAdapter.Stub(s => s.TryResolveMember(config.Members.Single(m => m.ID == "System")))
        .Return(SystemStorageMember);
    }

    protected StorageMember GetLdapInfo(NtfsStorageAdapter ntfsStorageAdapter, StorageMember storageMember)
    {
      // ReSharper disable PossibleUnintendedReferenceComparison
      Member member = new[] { AdminsStorageMember, UsersStorageMember }.Any(x => x == storageMember)
        ? new Member(storageMember.ID, storageMember.TargetMember.ToString(), "SamAccountName", MemberType.Group)
        : new Member(storageMember.ID, storageMember.TargetMember.ToString(), "SamAccountName", MemberType.User);
      // ReSharper restore PossibleUnintendedReferenceComparison

      string filter = ntfsStorageAdapter.BuildLdapSearchFilter(member, null);
      var result = ntfsStorageAdapter.QueryActiveDirectory(member, filter, null);
      var mi = ntfsStorageAdapter.CreateStorageMember(result[0].Properties);
      return mi;
    }

    protected bool DoRightsDiffer(string rights1, string rights2)
    {
      var parsedRights1 = ParseRights(rights1);
      var parsedRights2 = ParseRights(rights2);

      var differ = !Equals(parsedRights1, parsedRights2);
      TestContext.WriteLine(@"DoRightsDiffer: ({0} != {1}) ? {2}", parsedRights1, parsedRights2, differ);
      return differ;
    }

    protected FileSystemRights? ParseRights(string rights)
    {
      return string.IsNullOrWhiteSpace(rights) ? new FileSystemRights?() : (FileSystemRights)Enum.Parse(typeof(FileSystemRights), rights);
    }

    protected ApplicatorContext CreateUnitTestContext()
    {
      Contract.Configuration.Configuration config = LoadConfig("ConfigurationApplicator.xml");

      CreateStorageAdapterMock(config);

      var context = new ApplicatorContext(config)
                      {
                        StorageAdapter = StorageAdapter,
                        TargetSystem = "Mock",
                        Job = new Job()
                      };
      InitTraceSource(context.Job);
      return context;
    }
  }
}